# -*- coding: utf-8 -*-

import itertools
import pymongo
from conf import config as conf
import common
from common import mongodbs, dbrecord_to_dict, log

class StatisticsError(Exception):
    pass

class StatisticsWriter(object):
    def __init__(self, data_saver):
        self._allowed_metric = set(['failure', 'success_insert', 'success_update'])
        self._topic_manager = data_saver.topic_manager
        # self._data_collection_dict = {}
        # self._stats_collection_dict = {}

        # 建立统计数据的表，建立topic_id, date的复合索引，加unique约束。建立date的单字段索引，不加unique。
        db_name = conf.MONGODB['default_db']
        self._stats_collection = mongodbs[db_name][conf.STATISTICS_COLLECTION_NAME]
        self._stats_collection.create_index(
            [
                ('metadata.topic_id', pymongo.ASCENDING),
                ('metadata.date', pymongo.ASCENDING)
            ],
            background = True,
            unique = True
        );
        self._stats_collection.create_index(
            [
                ('metadata.date', pymongo.ASCENDING)
            ],
            background = True
        );

    def log_failure(self, task):
        return self.log_stats_data(task.topic_id, task.accept_time, 'failure')

    def log_success_insert(self, task):
        return self.log_stats_data(task.topic_id, task.accept_time, 'success_insert')

    def log_success_update(self, task):
        return self.log_stats_data(task.topic_id, task.accept_time, 'success_update')

    def __init_stats_document(self, metadata):
        # 这个函数开销比较大, 不过一天最多只执行一次
        # 不能直接将一个完整文档写进去, 因为有可能同时有其它线程或data_saver实例在写
        hourly_fields = [
            'hourly.%s' % i
            for i in range(24)
        ]
        minute_fields = [
            'minute.%s.%s' % (i,j)
            for i, j in itertools.product(range(24), range(60))
        ]
        daily_fields = [ 'daily' ]

        all_field_names = [
            '%s.%s' % (metric, field)
            for metric, field in itertools.product(self._allowed_metric, hourly_fields + minute_fields + daily_fields)
        ]
        write_requests = [
            pymongo.operations.UpdateOne(
                filter = {
                    'metadata': metadata,
                    field: {'$exists': False } 
                },
                update = {
                    '$set': { field: 0 }
                }
            )
            for field in all_field_names
        ]
        write_requests += [
            pymongo.operations.UpdateOne(
                filter = { 'metadata': metadata },
                update = { '$set': { 'rechecked': False } }
            ),
            pymongo.operations.UpdateOne(
                filter = { 'metadata': metadata },
                update = { '$set': { 'recheck_start_time': 0 } }
            )
        ]
        self._stats_collection.bulk_write(write_requests, ordered = False)

    def log_stats_data(self, topic_id, utime, metric):
        if not metric in self._allowed_metric:
            raise StatisticsError('metric[%s] is not allowed!!' % (metric))

        metadata = { 
            'date': utime.strftime(common.DATE_STR_FORMAT),
            'topic_id': topic_id
        }
        query = {
            'metadata': metadata,
        }
        update = { 
            '$inc': {
                '%s.daily' % (metric, ): 1,
                '%s.hourly.%d' % (metric, utime.hour): 1,
                '%s.minute.%d.%d' % (metric, utime.hour, utime.minute): 1 
            } 
        }
        write_result = self._stats_collection.update_one(query, update, upsert=True)

        if write_result.matched_count == 0:     # 说明是一条新记录
            self.__init_stats_document(metadata)
